home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / aminet / util / gnu / emacs_src_18_58.lha / emacs-18.58 / lisp / dabbrev.el < prev    next >
Lisp/Scheme  |  1992-02-21  |  9KB  |  222 lines

  1. ;; Dynamic abbreviation package for GNU Emacs.
  2. ;; Copyright (C) 1985, 1986 Free Software Foundation, Inc.
  3.  
  4. ;; This file is part of GNU Emacs.
  5.  
  6. ;; GNU Emacs is free software; you can redistribute it and/or modify
  7. ;; it under the terms of the GNU General Public License as published by
  8. ;; the Free Software Foundation; either version 1, or (at your option)
  9. ;; any later version.
  10.  
  11. ;; GNU Emacs is distributed in the hope that it will be useful,
  12. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. ;; GNU General Public License for more details.
  15.  
  16. ;; You should have received a copy of the GNU General Public License
  17. ;; along with GNU Emacs; see the file COPYING.  If not, write to
  18. ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  
  20.  
  21. ; DABBREVS - "Dynamic abbreviations" hack, originally written by Don Morrison
  22. ; for Twenex Emacs.  Converted to mlisp by Russ Fish.  Supports the table
  23. ; feature to avoid hitting the same expansion on re-expand, and the search
  24. ; size limit variable.  Bugs fixed from the Twenex version are flagged by
  25. ; comments starting with ;;; .
  26. ; converted to elisp by Spencer Thomas.
  27. ; Thoroughly cleaned up by Richard Stallman.
  28. ;  
  29. ; If anyone feels like hacking at it, Bob Keller (Keller@Utah-20) first
  30. ; suggested the beast, and has some good ideas for its improvement, but
  31. ; doesn?tknow TECO (the lucky devil...).  One thing that should definitely
  32. ; be done is adding the ability to search some other buffer(s) if you can?t
  33. ; find the expansion you want in the current one.
  34.  
  35. ;; (defun dabbrevs-help ()
  36. ;;   "Give help about dabbrevs."
  37. ;;   (interactive)
  38. ;;   (&info "emacs" "dabbrevs")    ; Select the specific info node.
  39. ;; )
  40. (provide 'dabbrevs)
  41.  
  42. (defvar dabbrevs-limit nil
  43.   "*Limits region searched by dabbrevs-expand to that many chars away (local).")
  44. (make-variable-buffer-local 'dabbrevs-limit)
  45.  
  46. (defvar dabbrevs-backward-only nil
  47.   "*If non-NIL, dabbrevs-expand only looks backwards.")
  48.  
  49. ; State vars for dabbrevs-re-expand.
  50. (defvar last-dabbrevs-table nil
  51.   "Table of expansions seen so far. (local)")
  52. (make-variable-buffer-local 'last-dabbrevs-table)
  53.  
  54. (defvar last-dabbrevs-abbreviation ""
  55.   "Last string we tried to expand.  Buffer-local.")
  56. (make-variable-buffer-local 'last-dabbrevs-abbreviation)
  57.  
  58. (defvar last-dabbrevs-direction 0
  59.   "Direction of last dabbrevs search. (local)")
  60. (make-variable-buffer-local 'last-dabbrevs-direction)
  61.  
  62. (defvar last-dabbrevs-abbrev-location nil
  63.   "Location last abbreviation began (local).")
  64. (make-variable-buffer-local 'last-dabbrevs-abbrev-location)
  65.  
  66. (defvar last-dabbrevs-expansion nil
  67.     "Last expansion of an abbreviation. (local)")
  68. (make-variable-buffer-local 'last-dabbrevs-expansion)
  69.  
  70. (defvar last-dabbrevs-expansion-location nil
  71.   "Location the last expansion was found. (local)")
  72. (make-variable-buffer-local 'last-dabbrevs-expansion-location)
  73.  
  74. (defun dabbrev-expand (arg)
  75.   "Expand previous word \"dynamically\".
  76. Expands to the most recent, preceding word for which this is a prefix.
  77. If no suitable preceding word is found, words following point are considered.
  78.  
  79. A positive prefix argument, N, says to take the Nth backward DISTINCT
  80. possibility.  A negative argument says search forward.  The variable
  81. dabbrev-backward-only may be used to limit the direction of search to
  82. backward if set non-nil.
  83.  
  84. If the cursor has not moved from the end of the previous expansion and
  85. no argument is given, replace the previously-made expansion
  86. with the next possible expansion not yet tried."
  87.   (interactive "*P")
  88.   (let (abbrev expansion old which loc n pattern
  89.     (do-case (and case-fold-search case-replace)))
  90.     ;; abbrev -- the abbrev to expand
  91.     ;; expansion -- the expansion found (eventually) or nil until then
  92.     ;; old -- the text currently in the buffer
  93.     ;;    (the abbrev, or the previously-made expansion)
  94.     ;; loc -- place where expansion is found
  95.     ;;    (to start search there for next expansion if requested later)
  96.     ;; do-case -- nil if should consider case significant.
  97.     (save-excursion
  98.       (if (and (null arg)
  99.            (eq last-command this-command)
  100.            last-dabbrevs-abbrev-location)
  101.       (progn
  102.         (setq abbrev last-dabbrevs-abbreviation)
  103.         (setq old last-dabbrevs-expansion)
  104.         (setq which last-dabbrevs-direction))
  105.     (setq which (if (null arg)
  106.             (if dabbrevs-backward-only 1 0)
  107.                 (prefix-numeric-value arg)))
  108.     (setq loc (point))
  109.     (forward-word -1)
  110.     (setq last-dabbrevs-abbrev-location (point)) ; Original location.
  111.     (setq abbrev (buffer-substring (point) loc))
  112.     (setq old abbrev)
  113.     (setq last-dabbrevs-expansion-location nil)
  114.     (setq last-dabbrev-table nil))      ; Clear table of things seen.
  115.  
  116.       (setq pattern (concat "\\b" (regexp-quote abbrev) "\\(\\sw\\|\\s_\\)+"))
  117.       ;; Try looking backward unless inhibited.
  118.       (if (>= which 0)
  119.       (progn 
  120.         (setq n (max 1 which))
  121.         (if last-dabbrevs-expansion-location
  122.         (goto-char last-dabbrevs-expansion-location))
  123.         (while (and (> n 0)
  124.             (setq expansion (dabbrevs-search pattern t do-case)))
  125.           (setq loc (point-marker))
  126.           (setq last-dabbrev-table (cons expansion last-dabbrev-table))
  127.           (setq n (1- n)))
  128.         (or expansion
  129.         (setq last-dabbrevs-expansion-location nil))
  130.         (setq last-dabbrevs-direction (min 1 which))))
  131.  
  132.       (if (and (<= which 0) (not expansion)) ; Then look forward.
  133.       (progn 
  134.         (setq n (max 1 (- which)))
  135.         (if last-dabbrevs-expansion-location
  136.         (goto-char last-dabbrevs-expansion-location))
  137.         (while (and (> n 0)
  138.             (setq expansion (dabbrevs-search pattern nil do-case)))
  139.           (setq loc (point-marker))
  140.           (setq last-dabbrev-table (cons expansion last-dabbrev-table))
  141.           (setq n (1- n)))
  142.         (setq last-dabbrevs-direction -1))))
  143.  
  144.     (if (not expansion)
  145.     (let ((first (string= abbrev old)))
  146.       (setq last-dabbrevs-abbrev-location nil)
  147.       (if (not first)
  148.           (progn (undo-boundary)
  149.              (delete-backward-char (length old))
  150.              (insert abbrev)))
  151.       (error (if first
  152.              "No dynamic expansion for \"%s\" found."
  153.              "No further dynamic expansions for \"%s\" found.")
  154.          abbrev))
  155.       ;; Success: stick it in and return.
  156.       (undo-boundary)
  157.       (search-backward old)
  158.       ;; Make case of replacement conform to case of abbreviation
  159.       ;; provided (1) that kind of thing is enabled in this buffer
  160.       ;; and (2) the replacement itself is all lower case
  161.       ;; except perhaps for the first character.
  162.       (let ((do-case (and do-case
  163.               (string= (substring expansion 1)
  164.                    (downcase (substring expansion 1))))))
  165.     ;; First put back the original abbreviation with its original
  166.     ;; case pattern.
  167.     (save-excursion
  168.       (replace-match abbrev t 'literal))
  169.     (search-forward abbrev)
  170.     (replace-match (if do-case (downcase expansion) expansion)
  171.                (not do-case)
  172.                'literal))
  173.       ;; Save state for re-expand.
  174.       (setq last-dabbrevs-abbreviation abbrev)
  175.       (setq last-dabbrevs-expansion expansion)
  176.       (setq last-dabbrevs-expansion-location loc))))
  177.  
  178. ;; Search function used by dabbrevs library.  
  179. ;; First arg is string to find as prefix of word.  Second arg is
  180. ;; t for reverse search, nil for forward.  Variable dabbrevs-limit
  181. ;; controls the maximum search region size.
  182.  
  183. ;; Table of expansions already seen is examined in buffer last-dabbrev-table,
  184. ;; so that only distinct possibilities are found by dabbrevs-re-expand.
  185. ;; Note that to prevent finding the abbrev itself it must have been
  186. ;; entered in the table.
  187.  
  188. ;; Value is the expansion, or nil if not found.  After a successful
  189. ;; search, point is left right after the expansion found.
  190.  
  191. (defun dabbrevs-search (pattern reverse do-case)
  192.   (let (missing result)
  193.     (save-restriction         ; Uses restriction for limited searches.
  194.       (if dabbrevs-limit
  195.       (narrow-to-region last-dabbrevs-abbrev-location
  196.                 (+ (point)
  197.                    (* dabbrevs-limit (if reverse -1 1)))))
  198.       ;; Keep looking for a distinct expansion.
  199.       (setq result nil)
  200.       (setq missing nil)
  201.       (while  (and (not result) (not missing))
  202.     ; Look for it, leave loop if search fails.
  203.     (setq missing
  204.           (not (if reverse
  205.                (re-search-backward pattern nil t)
  206.                (re-search-forward pattern nil t))))
  207.  
  208.     (if (not missing)
  209.         (progn
  210.           (setq result (buffer-substring (match-beginning 0)
  211.                          (match-end 0)))
  212.           (let* ((test last-dabbrev-table))
  213.         (while (and test
  214.                 (not
  215.                  (if do-case
  216.                  (string= (downcase (car test)) (downcase result))
  217.                    (string= (car test) result))))
  218.           (setq test (cdr test)))
  219.         (if test (setq result nil))))))    ; if already in table, ignore
  220.       result)))
  221.